﻿using System;
using Engine;
using Engine.Graphics;
using GameEntitySystem;
using TemplatesDatabase;

namespace Game
{
    public class ComponentNewFirstPersonModel : ComponentFirstPersonModel, IDrawable, IUpdateable
    {
        public readonly PrimitivesRenderer2D m_primitivesRenderer2D = new PrimitivesRenderer2D();

        public ComponentClothing m_componentClothing;

        public ComponentAimingSights m_componentAimingSights;

        public float BoltOffset;

        public bool IsScopeOpening;

        public bool IsFClicked;

        public BevelledButtonWidget AimButton;

        public new int[] DrawOrders => new int[1] { 2000 };

        public bool ToggleScope => IsFClicked || AimButton.IsClicked;

        public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
        {
            base.Load(valuesDictionary, idToEntityMap);
            m_componentClothing = base.Entity.FindComponent<ComponentClothing>();
            m_componentAimingSights = base.Entity.FindComponent<ComponentAimingSights>();
            AimButton = m_componentPlayer.GameWidget.Children.Find<BevelledButtonWidget>("AimButton");
        }

        public new void Draw(Camera camera, int drawOrder)
        {
            if (!(m_componentPlayer.ComponentHealth.Health > 0f) || !camera.GameWidget.IsEntityFirstPersonTarget(base.Entity))
            {
                return;
            }

            if (BlocksManager.Blocks[Terrain.ExtractContents(m_componentMiner.ActiveBlockValue)] is TestGunsBlock)
            {
                float x = camera.ViewportSize.X;
                float y = camera.ViewportSize.Y;
                if (IsScopeOpening)
                {
                    TexturedBatch2D texturedBatch2D = m_primitivesRenderer2D.TexturedBatch(ContentManager.Get<Texture2D>("Textures/FCGun/SniperSights"), useAlphaTest: false, 0, DepthStencilState.None, null, null, SamplerState.LinearWrap);
                    int count = texturedBatch2D.TriangleVertices.Count;
                    texturedBatch2D.QueueQuad(new Vector2(x / 2f - y / 2f, 0f), new Vector2(x / 2f + y / 2f, y), 0f, Vector2.Zero, Vector2.One, Color.White);
                    texturedBatch2D.TransformTriangles(camera.ViewportMatrix, count);
                    FlatBatch2D flatBatch2D = m_primitivesRenderer2D.FlatBatch(0, DepthStencilState.DepthWrite);
                    flatBatch2D.QueueQuad(Vector2.Zero, new Vector2(x / 2f - y / 2f, y), 0f, Color.Black);
                    flatBatch2D.QueueQuad(new Vector2(x / 2f + y / 2f, 0f), camera.ViewportSize, 0f, Color.Black);
                    flatBatch2D.TransformTriangles(camera.ViewportMatrix);
                }
                else
                {
                    float num = 80f;
                    TexturedBatch2D texturedBatch2D2 = m_primitivesRenderer2D.TexturedBatch(ContentManager.Get<Texture2D>("Textures/FCGun/Sights2"), useAlphaTest: false, 0, DepthStencilState.None, null, null, SamplerState.LinearWrap);
                    int count2 = texturedBatch2D2.TriangleVertices.Count;
                    texturedBatch2D2.QueueQuad(new Vector2(x / 2f - num, y / 2f - num), new Vector2(x / 2f + num, y / 2f + num), 0f, Vector2.Zero, Vector2.One, Color.White);
                    texturedBatch2D2.TransformTriangles(camera.ViewportMatrix, count2);
                }

                m_primitivesRenderer2D.Flush();
            }

            Viewport viewport = Display.Viewport;
            Viewport viewport2 = viewport;
            viewport2.MaxDepth *= 0.1f;
            Display.Viewport = viewport2;
            try
            {
                Matrix identity = Matrix.Identity;
                if (m_swapAnimationTime > 0f)
                {
                    float num2 = MathUtils.Pow(MathUtils.Sin(m_swapAnimationTime * (float)Math.PI), 3f);
                    identity *= Matrix.CreateTranslation(0f, -0.8f * num2, 0.2f * num2);
                }

                if (m_pokeAnimationTime > 0f)
                {
                    float num3 = MathUtils.Sin(MathUtils.Sqrt(m_pokeAnimationTime) * (float)Math.PI);
                    if (m_value != 0)
                    {
                        identity *= Matrix.CreateRotationX((0f - MathUtils.DegToRad(90f)) * num3);
                        identity *= Matrix.CreateTranslation(-0.5f * num3, 0.1f * num3, 0f * num3);
                    }
                    else
                    {
                        identity *= Matrix.CreateRotationX((0f - MathUtils.DegToRad(45f)) * num3);
                        identity *= Matrix.CreateTranslation(-0.1f * num3, 0.2f * num3, -0.05f * num3);
                    }
                }

                if (m_componentRider.Mount != null)
                {
                    ComponentCreatureModel componentCreatureModel = m_componentRider.Mount.Entity.FindComponent<ComponentCreatureModel>();
                    if (componentCreatureModel != null)
                    {
                        float num4 = componentCreatureModel.MovementAnimationPhase * (float)Math.PI * 2f + 0.5f;
                        Vector3 position = default(Vector3);
                        position.Y = 0.02f * MathUtils.Sin(num4);
                        position.Z = 0.02f * MathUtils.Sin(num4);
                        identity *= Matrix.CreateRotationX(0.05f * MathUtils.Sin(num4 * 1f)) * Matrix.CreateTranslation(position);
                    }
                }
                else
                {
                    float num5 = m_componentPlayer.ComponentCreatureModel.MovementAnimationPhase * (float)Math.PI * 2f;
                    Vector3 position2 = default(Vector3);
                    position2.X = 0.03f * MathUtils.Sin(num5 * 1f);
                    position2.Y = 0.02f * MathUtils.Sin(num5 * 2f);
                    position2.Z = 0.02f * MathUtils.Sin(num5 * 1f);
                    identity *= Matrix.CreateRotationZ(1f * position2.X) * Matrix.CreateTranslation(position2);
                }

                Vector3 eyePosition = m_componentPlayer.ComponentCreatureModel.EyePosition;
                int x2 = Terrain.ToCell(eyePosition.X);
                int num6 = Terrain.ToCell(eyePosition.Y);
                int z = Terrain.ToCell(eyePosition.Z);
                Matrix matrix = Matrix.CreateFromQuaternion(m_componentPlayer.ComponentCreatureModel.EyeRotation);
                matrix.Translation = m_componentPlayer.ComponentCreatureModel.EyePosition;
                if (m_value != 0)
                {
                    if (num6 >= 0 && num6 <= 255)
                    {
                        TerrainChunk chunkAtCell = m_subsystemTerrain.Terrain.GetChunkAtCell(x2, z);
                        if (chunkAtCell != null && chunkAtCell.State >= TerrainChunkState.InvalidVertices1)
                        {
                            m_itemLight = m_subsystemTerrain.Terrain.GetCellLightFast(x2, num6, z);
                        }
                    }

                    int num7 = Terrain.ExtractContents(m_value);
                    Block block = BlocksManager.Blocks[num7];
                    Vector3 vector = block.GetFirstPersonRotation(m_value) * ((float)Math.PI / 180f) + m_itemRotation;
                    Vector3 position3 = block.GetFirstPersonOffset(m_value) + m_itemOffset;
                    position3 += m_itemOffset;
                    Matrix matrix2 = Matrix.CreateFromYawPitchRoll(vector.Y, vector.X, vector.Z) * identity * Matrix.CreateTranslation(position3) * Matrix.CreateFromYawPitchRoll(m_lagAngles.X, m_lagAngles.Y, 0f) * matrix;
                    m_drawBlockEnvironmentData.DrawBlockMode = DrawBlockMode.FirstPerson;
                    m_drawBlockEnvironmentData.SubsystemTerrain = m_subsystemTerrain;
                    m_drawBlockEnvironmentData.InWorldMatrix = matrix2;
                    m_drawBlockEnvironmentData.Light = m_itemLight;
                    m_drawBlockEnvironmentData.Humidity = m_subsystemTerrain.Terrain.GetSeasonalHumidity(x2, z);
                    m_drawBlockEnvironmentData.Temperature = m_subsystemTerrain.Terrain.GetSeasonalTemperature(x2, z) + SubsystemWeather.GetTemperatureAdjustmentAtHeight(num6);
                    if (block is TestGunsBlock testGunsBlock)
                    {
                        Texture2D innerClothedTexture = m_componentClothing.InnerClothedTexture;
                        testGunsBlock.DrawGun(m_primitivesRenderer, Color.White, block.GetFirstPersonScale(m_value), ref matrix2, m_drawBlockEnvironmentData);
                        testGunsBlock.DrawArms(m_primitivesRenderer, Color.White, block.GetFirstPersonScale(m_value), ref matrix2, m_drawBlockEnvironmentData, innerClothedTexture);
                        Matrix matrix3 = Matrix.CreateTranslation(0f, 0f, BoltOffset) * matrix2;
                        testGunsBlock.DrawBolt(m_primitivesRenderer, Color.White, block.GetFirstPersonScale(m_value), ref matrix3, m_drawBlockEnvironmentData);
                    }
                    else
                    {
                        block.DrawBlock(m_primitivesRenderer, m_value, Color.White, block.GetFirstPersonScale(m_value), ref matrix2, m_drawBlockEnvironmentData);
                    }

                    m_primitivesRenderer.Flush(camera.ViewProjectionMatrix);
                    return;
                }

                if (Time.FrameStartTime >= m_nextHandLightTime)
                {
                    float? num8 = LightingManager.CalculateSmoothLight(m_subsystemTerrain, eyePosition);
                    if (num8.HasValue)
                    {
                        m_nextHandLightTime = Time.FrameStartTime + 0.1;
                        m_handLight = num8.Value;
                    }
                }

                Vector3 position4 = new Vector3(0.25f, -0.3f, -0.05f);
                Matrix matrix4 = Matrix.CreateScale(0.01f) * Matrix.CreateRotationX(0.8f) * Matrix.CreateRotationY(0.4f) * identity * Matrix.CreateTranslation(position4) * Matrix.CreateFromYawPitchRoll(m_lagAngles.X, m_lagAngles.Y, 0f) * matrix * camera.ViewMatrix;
                Display.DepthStencilState = DepthStencilState.Default;
                Display.RasterizerState = RasterizerState.CullCounterClockwiseScissor;
                ComponentFirstPersonModel.LitShader.Texture = m_componentPlayer.ComponentCreatureModel.TextureOverride;
                ComponentFirstPersonModel.LitShader.SamplerState = SamplerState.PointClamp;
                ComponentFirstPersonModel.LitShader.MaterialColor = Vector4.One;
                ComponentFirstPersonModel.LitShader.AmbientLightColor = new Vector3(m_handLight * LightingManager.LightAmbient);
                ComponentFirstPersonModel.LitShader.DiffuseLightColor1 = new Vector3(m_handLight);
                ComponentFirstPersonModel.LitShader.DiffuseLightColor2 = new Vector3(m_handLight);
                ComponentFirstPersonModel.LitShader.LightDirection1 = Vector3.TransformNormal(LightingManager.DirectionToLight1, camera.ViewMatrix);
                ComponentFirstPersonModel.LitShader.LightDirection2 = Vector3.TransformNormal(LightingManager.DirectionToLight2, camera.ViewMatrix);
                ComponentFirstPersonModel.LitShader.Transforms.World[0] = matrix4;
                ComponentFirstPersonModel.LitShader.Transforms.View = Matrix.Identity;
                ComponentFirstPersonModel.LitShader.Transforms.Projection = camera.ProjectionMatrix;
                foreach (ModelMesh mesh in m_handModel.Meshes)
                {
                    foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    {
                        Display.DrawIndexed(PrimitiveType.TriangleList, ComponentFirstPersonModel.LitShader, meshPart.VertexBuffer, meshPart.IndexBuffer, meshPart.StartIndex, meshPart.IndicesCount);
                    }
                }
            }
            finally
            {
                Display.Viewport = viewport;
            }
        }

        public new void Update(float dt)
        {
            BoltOffset = MathUtils.Lerp(BoltOffset, 0f, MathUtils.Saturate(5f * dt));
            Vector3 vector = m_componentPlayer.ComponentCreatureModel.EyeRotation.ToYawPitchRoll();
            m_lagAngles *= MathUtils.Pow(0.2f, dt);
            if (m_lastYpr.HasValue)
            {
                Vector3 vector2 = vector - m_lastYpr.Value;
                m_lagAngles.X = MathUtils.Clamp(m_lagAngles.X - 0.08f * MathUtils.NormalizeAngle(vector2.X), -0.1f, 0.1f);
                m_lagAngles.Y = MathUtils.Clamp(m_lagAngles.Y - 0.08f * MathUtils.NormalizeAngle(vector2.Y), -0.1f, 0.1f);
            }

            m_lastYpr = vector;
            int activeBlockValue = m_componentMiner.ActiveBlockValue;
            if (activeBlockValue != m_value)
            {
                if (Terrain.ExtractContents(activeBlockValue) != Terrain.ExtractContents(m_value) && IsScopeOpening)
                {
                    ScopeOff();
                }

                if (m_swapAnimationTime == 0f)
                {
                    if (BlocksManager.Blocks[Terrain.ExtractContents(activeBlockValue)].IsSwapAnimationNeeded(m_value, activeBlockValue))
                    {
                        m_swapAnimationTime = 0.0001f;
                    }
                    else
                    {
                        m_value = activeBlockValue;
                    }
                }
            }

            if (m_swapAnimationTime > 0f)
            {
                float swapAnimationTime = m_swapAnimationTime;
                m_swapAnimationTime += 2f * dt;
                if (swapAnimationTime < 0.5f && m_swapAnimationTime >= 0.5f)
                {
                    m_value = activeBlockValue;
                }

                if (m_swapAnimationTime > 1f)
                {
                    m_swapAnimationTime = 0f;
                }
            }

            m_pokeAnimationTime = m_componentMiner.PokingPhase;
            m_itemOffset = Vector3.Lerp(m_itemOffset, base.ItemOffsetOrder, MathUtils.Saturate(10f * dt));
            m_itemRotation = Vector3.Lerp(m_itemRotation, base.ItemRotationOrder, MathUtils.Saturate(10f * dt));
            base.ItemOffsetOrder = Vector3.Zero;
            base.ItemRotationOrder = Vector3.Zero;
            if (!(BlocksManager.Blocks[Terrain.ExtractContents(activeBlockValue)] is TestGunsBlock))
            {
                return;
            }

            TestGunData gunData = GunTestManager.GetGunData(Terrain.ExtractContents(activeBlockValue));
            if (gunData == null || !gunData.IsScopeEnable)
            {
                return;
            }

            if (ToggleScope)
            {
                if (IsScopeOpening)
                {
                    ScopeOff();
                }
                else
                {
                    GameWidget gameWidget = m_componentPlayer.GameWidget;
                    gameWidget.ActiveCamera = ((gameWidget.ActiveCamera is TestLensCamera) ? gameWidget.FindCamera<FppCamera>() : new TestLensCamera(gameWidget));
                    IsScopeOpening = true;
                }
            }

            if (IsScopeOpening)
            {
                m_componentAimingSights.ShowAimingSights(m_componentPlayer.ComponentBody.Position, -Vector3.UnitY);
            }
        }

        public void ScopeOff()
        {
            GameWidget gameWidget = m_componentPlayer.GameWidget;
            gameWidget.ActiveCamera = gameWidget.FindCamera<FppCamera>();
            IsScopeOpening = false;
        }
    }
}